package com.cloudpivot.receivales.workorder.service.impl;

import cn.hutool.core.img.ImgUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cloudpivot.receivales.ding.basic.service.impl.HttpAPIServiceForDing;
import com.cloudpivot.receivales.ding.util.DingUtil;
import com.cloudpivot.receivales.meta.service.impl.FileHandleServiceImpl;
import com.cloudpivot.receivales.workorder.domain.AnnotaionsDTO;
import com.cloudpivot.receivales.workorder.domain.RspReportDTO;
import com.cloudpivot.receivales.workorder.domain.TechnicalWorkDTO;
import com.cloudpivot.receivales.workorder.domain.WorkorderReportDTO;
import com.cloudpivot.receivales.workorder.service.WorkorderPoiService;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.*;
import com.deepoove.poi.util.PoitlIOUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

/**
 * 工单 报告服务
 */
@Service
@Slf4j
public class WorkorderPoiServiceImpl implements WorkorderPoiService {


    @Autowired
    private HttpAPIServiceForDing httpAPIServiceForDing;
    @Autowired
    private FileHandleServiceImpl fileHandleService;
    @Value("${workorder.modepath}")
    private String MODEPATH;

    @Value("${workorder.outdic}")
    private String OUTPATH;

    @Value("${myprops.cpurl}")
    private String CPURL;

    @Value("${myprops.crmurl}")
    private String CRMURL;
    @Value("${fontinfo.tmppath}")
    private String FILEPATH;
    @Value("${fontinfo.path}")
    private String FONTPATH;

    /**
     * 创建 工单报告 无签名
     *
     * @param entity
     */
    @Override
    public void createWorkorderReportFile(WorkorderReportDTO entity) {
        try {
            XWPFTemplate template = XWPFTemplate.compile(MODEPATH + "workorderprintmode.docx");
            template.render(entity);

            template.writeAndClose(new FileOutputStream(OUTPATH + "123.docx"));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 使用url做签名 没用
     *
     * @param entity
     * @param url
     */
    @Override
    public void createWorkorderFileBySignUrl(WorkorderReportDTO entity, String url) {
        return ;
    }

    /**
     * 使用base64 报告模版
     *
     * @param entity
     * @param base64Sign
     */
    @Override
    public void createWorkorderFileBySignbase64(WorkorderReportDTO entity, String base64Sign) {

        PictureRenderData pictures = Pictures.ofBase64(base64Sign, PictureType.PNG).size(80, 50).create();
        entity.setCus_sign(pictures);
        try {
            //处理子表
            entity.setWx_table(buildTable(entity));
            //模版处理
            XWPFTemplate template = XWPFTemplate.compile(MODEPATH + "workorderprintmode.docx");
            template.render(entity);
            String fileName = "ReportSign-" + System.currentTimeMillis() + ".docx";
            template.writeAndClose(new FileOutputStream(OUTPATH + fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 模版生成签字文档 by base64 输出流
     * @param entity
     * @param refId
     */
    @Override
    public Map<String, Object> createWorkorderStreamBySignbase64(WorkorderReportDTO entity, String refId) {
        Map<String, Object> rspMap = new HashMap<>();
        if(StringUtils.isNotBlank(refId)){
            PictureRenderData pictures = Pictures.ofBase64(getSignBase64(refId), PictureType.PNG).size(90, 50).altMeta("无签名").create();
            entity.setCus_sign(pictures);
        }
        try {
            //处理子表
            TableRenderData _wxTable=buildTable(entity);
            if (!Objects.isNull(_wxTable)) {
                //子表处理异常
                log.info("------->>工单报告子表处理异常>>>>");
                entity.setWx_table(buildTable(entity));
            }
            //模版处理
            XWPFTemplate template = XWPFTemplate.compile(MODEPATH + "workorderprintmode.docx");
            template.render(entity);
            String fileName = "ReportSign-" + System.currentTimeMillis() + ".docx";
            //字符流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            template.write(out);
            byte[] bytes = out.toByteArray();
            out.close();
            PoitlIOUtils.closeQuietlyMulti(template, out);
            rspMap.put("fileName", fileName);
            rspMap.put("bytes", bytes);
            return rspMap;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 技术工单模版生成
     * @param entity
     * @return
     */
    @Override
    public Map<String, Object> createTechnicalWorkBySignbase64(TechnicalWorkDTO entity) {
        Map<String, Object> rspMap = new HashMap<>();
        if (entity.getSite_signature().equals("是")){
            PictureRenderData pictures = Pictures.ofBase64(getSignBase64(entity.getSignid()), PictureType.PNG).size(90, 50).altMeta("无签名").create();
            entity.setCus_sign(pictures);
            // 生成 Word 文档
            try (XWPFTemplate template = XWPFTemplate.compile(MODEPATH + "TechnicalWorkprintmode.docx");
                 ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                template.render(entity);
                template.write(out);

                String fileName = "ReportSign-" + System.currentTimeMillis() + ".pdf";
                byte[] bytes = out.toByteArray();
                File file = bytesToFile(bytes, "output.docx");
                byte[] bytesFile = fileHandleService.fileToPdf(file,"docx");
                rspMap.put("fileName", fileName);
                rspMap.put("bytes", bytesFile);
                // 使用Base64类将byte[]转换为Base64字符串
                String base64String = Base64.getEncoder().encodeToString(bytesFile);
                addTechnicalWorkAnnotations(base64String,entity.getGuid());
            } catch (IOException e) {
                e.printStackTrace();
                // 可以添加日志记录或其他异常处理逻辑
                return null;
            }
        }else {
            addTechnicalWorkAnnotations(entity.getWork_order(),entity.getGuid());
        }


        return rspMap;
    }

    private File bytesToFile(byte[] bytes, String filePath) {
        File file = new File(filePath);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(bytes);
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return file;
    }


    /**
     * 获取工单记录
     *
     * @param crmid
     */
    @Override
    public WorkorderReportDTO getWorkOrderDetail(String crmid) {
        String expand1 = "new_account($select=name),new_contact($select=lastname),new_account_equipment($select=new_name,new_trademark,new_product_name,new_equipment_type,new_model),new_department($select=name),new_before($select=new_name),new_return_visit_name($select=lastname),owninguser($select=lastname),new_type_3($select=new_name),new_type_2($select=new_name)";
        String url1 = String.format("%snew_work_orders(%s)?$expand=%s", CRMURL, crmid, expand1);
        url1 = DingUtil.urlEcode(url1);
        log.info("请求crm url:{}", url1);

        String expand2 = "new_product($select=new_name)";
        String url2 = String.format("%snew_replacements?$filter=_new_word_order_value eq '%s' and statecode eq 0&$expand=%s", CRMURL, crmid, expand2);
        url2 = DingUtil.urlEcode(url2);
        log.info("请求crm url2:{}", url2);
        try {
            String ret1 = httpAPIServiceForDing.doGetCrm(url1);   //工单
            String ret2 = httpAPIServiceForDing.doGetCrm(url2); //配件明细
            JSONObject retJson1 = JSONObject.parseObject(ret1);
            JSONObject retJson2 = JSONObject.parseObject(ret2);
            WorkorderReportDTO dto = convertToReportDTO(retJson1, retJson2);
            log.info("report 对象：{}", JSONObject.toJSONString(dto));
            return dto;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }



    //crm工单 附件部分---------------------------------------------------------------

    /**
     * 获取 工单附件
     */
    @Override
    public RspReportDTO<AnnotaionsDTO> getWorkOrderAnnotations(String guid) {
        String url = String.format("%sannotations?$filter=filename eq '%s' and objecttypecode eq 'new_work_order' and _objectid_value eq '%s'", CRMURL, "reportSignFinish.docx", guid);
        url = DingUtil.urlEcode(url);
        try {
            String ret = httpAPIServiceForDing.doGetCrm(url);
            JSONObject json = JSONObject.parseObject(ret);
            JSONArray array = json.getJSONArray("value");
            if (array.size() > 1) {
                log.info("多个电子签名附件,无法获取");
                return new RspReportDTO(-1);
            }
            if (array.size() == 0) {
                log.info("没有签名");
                return new RspReportDTO(12);
            }
            JSONObject _j = (JSONObject) array.get(0);
            AnnotaionsDTO dto = JSONObject.toJavaObject(_j, AnnotaionsDTO.class);
            return new RspReportDTO(1, dto);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 新增 技术支持工单附件
     */
    @Override
    public String addTechnicalWorkAnnotations(String base64, String guid) {
        String url = String.format("%sannotations", CRMURL);
        url = DingUtil.urlEcode(url);

        //构建对象
        JSONObject reqJson = new JSONObject();
        reqJson.put("objecttypecode", "new_technology_work_order");
        reqJson.put("objectid_new_technology_work_order@odata.bind", "/new_technology_work_orders(" + guid + ")");
        reqJson.put("isdocument", true);
        reqJson.put("filename", "reportSignFinish.pdf");
        reqJson.put("documentbody", base64);

        try {
            String ret = httpAPIServiceForDing.doPostCrm(url, reqJson.toJSONString(), null);
            JSONObject json = JSONObject.parseObject(ret);
            String annotationid = json.getString("annotationid");
            log.info("新增附件成功-> guid：{}", annotationid);
            return annotationid;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 新增 工单附件
     */
    @Override
    public String addWorkOrderAnnotations(String base64, String guid) {
        String url = String.format("%sannotations", CRMURL);
        url = DingUtil.urlEcode(url);

        //构建对象
        JSONObject reqJson = new JSONObject();
        reqJson.put("objecttypecode", "new_work_order");
        reqJson.put("objectid_new_work_order@odata.bind", "/new_work_orders(" + guid + ")");
        reqJson.put("isdocument", true);
        reqJson.put("filename", "reportSignFinish.docx");
        reqJson.put("documentbody", base64);

        try {
            String ret = httpAPIServiceForDing.doPostCrm(url, reqJson.toJSONString(), null);
            JSONObject json = JSONObject.parseObject(ret);
            String annotationid = json.getString("annotationid");
            log.info("新增附件成功-> guid：{}", annotationid);
            return annotationid;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 删除工单 附件
     */
    public RspReportDTO delWorkOrderAnnotations(String guid) {
        String url = String.format("%sannotations(%s)", CRMURL, guid);
        url = DingUtil.urlEcode(url);

        try {
            String ret = httpAPIServiceForDing.doDelCrm(url);
//            if (StringUtils.isBlank(ret)) {
//                return new RspReportDTO(11);
//            }
            log.info("删除工单 已经存在的电子签名附件情况:{}", ret);
            return new RspReportDTO(11);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 创建子表对象
     *
     * @return
     */
    private TableRenderData buildTable(WorkorderReportDTO entity) {
        try {
            List<WorkorderReportDTO.WxItem> items = entity.getWxItems();
            //做表头
            RowRenderData rowTitle = Rows.of("序号", "配件名称", "零件号", "数量").center().textBold().create();

            if (Objects.isNull(items)) {
                RowRenderData[] args = new RowRenderData[1];
                args[0] = rowTitle;
                //只返回表头||返回空
                TableRenderData table = Tables.of(args).create();
                return table;
            } else {
                //返回表
                RowRenderData[] args = new RowRenderData[items.size() + 1];
                args[0] = rowTitle;
                for (int i = 0; i < items.size(); i++) {
                    WorkorderReportDTO.WxItem item = items.get(i);
                    //args[i + 1] = Rows.of(item.getNew_name(), item.getNew_productname(), item.getNew_add_code(), item.getNew_number(), item.getNew_price(), item.getNew_total()).center().create();
                    //列的上下一定要对上
                    args[i + 1] = Rows.of(item.getNew_name(), item.getNew_productname(), item.getNew_add_code(), item.getNew_number()).center().create();
                }
                TableRenderData table = Tables.of(args).create();
                return table;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取签名
     *  旋转-90度--默认
     * @param refId
     * @return
     */
    private String getSignBase64(String refId) {
        try {
            String url = String.format("%s%s%s", CPURL, "api/aliyun/download?refId=", refId);

            Base64.Encoder encoder = Base64.getEncoder();
            byte[] ret = httpAPIServiceForDing.doGetToBytes(url);
            String base64 = encoder.encodeToString(ret);
            BufferedImage inImage = ImgUtil.toImage(base64);
            Image outImage=ImgUtil.rotate(inImage, -90);
            String outBase64 = ImgUtil.toBase64(outImage, "png");
            System.out.println(outBase64.length());
            return outBase64;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }





    /**
     * 转换crm 工单 to reportDTO
     *
     * @param entity1
     * @return
     */
    private WorkorderReportDTO convertToReportDTO(JSONObject entity1, JSONObject entity2) {
        WorkorderReportDTO dto = new WorkorderReportDTO();
        dto.setNew_num(entity1.getString("new_num"));
        dto.setNew_accountname(getJsonInsideValue(entity1.getJSONObject("new_account"), "name"));
        dto.setNew_administrative(entity1.getString("new_administrative"));
        dto.setNew_contactname(getJsonInsideValue(entity1.getJSONObject("new_contact"), "lastname"));
        dto.setNew_con_tel(entity1.getString("new_con_tel"));
        dto.setOwneridname(getJsonInsideValue(entity1.getJSONObject("owninguser"), "lastname"));
        dto.setNew_problem_happen_time(getGMTToChinaShortDate(entity1.getString("new_problem_happen_time")));
        dto.setNew_arrival_time(getGMTToChinaShortDate(entity1.getString("new_arrival_time")));
        dto.setNew_resolution_time(getGMTToChinaShortDate(entity1.getString("new_resolution_time")));
        dto.setNew_departmentname(getJsonInsideValue(entity1.getJSONObject("new_department"), "name"));
        dto.setNew_type_3(getJsonInsideValue(entity1.getJSONObject("new_type_3"), "new_name"));  //和明细一致
        dto.setNew_type_2(getJsonInsideValue(entity1.getJSONObject("new_type_2"), "new_name"));  //和明细一致
        dto.setNew_service_hours(String.format("%.2f", entity1.getDouble("new_service_hours")));
        dto.setNew_service_reporting(entity1.getString("new_service_reporting"));
        dto.setNew_actual_problem_description(entity1.getString("new_actual_problem_description")); //问题描述
        //以下为仪器信息
        dto.setNew_account_equipmentname(getJsonInsideValue(entity1.getJSONObject("new_account_equipment"), "new_name"));
        dto.setNew_productname(getJsonInsideValue(entity1.getJSONObject("new_account_equipment"), "new_product_name"));
        dto.setNew_equipment_type(getJsonInsideValue(entity1.getJSONObject("new_account_equipment"), "new_model")); // 对象属性 有变化
        dto.setNew_trademark(getJsonInsideValue(entity1.getJSONObject("new_account_equipment"), "new_trademark"));
        //以下 更换配件明细
        JSONArray dtoItems = entity2.getJSONArray("value");
        List<WorkorderReportDTO.WxItem> items = new ArrayList<>();
        if (dtoItems.size() > 0) {
            //循环
            for (int i = 0; i < dtoItems.size(); i++) {
                JSONObject _json = (JSONObject) dtoItems.get(i);
                WorkorderReportDTO.WxItem item = new WorkorderReportDTO.WxItem();
                item.setNew_name(_json.getString("new_name"));
                item.setNew_productname(getJsonInsideValue(_json.getJSONObject("new_product"), "new_name"));
                item.setNew_add_code(_json.getString("new_add_code"));
                item.setNew_number(_json.getString("new_number"));
                //item.setNew_price(String.format("%.2f", _json.getDouble("new_price")));
                //item.setNew_total(String.format("%.2f", _json.getDouble("new_total")));
                items.add(item);
            }
            dto.setWxItems(items);
        }

        return dto;
    }

    /**
     * 工具方法，获取obj内部
     *
     * @return
     */
    public static String getJsonInsideValue(JSONObject jsonObject, String key) {
        try {
            if (jsonObject == null) {
                return null;
            } else {
                return jsonObject.getString(key);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 转换格林威治时间为东八区日期
     *
     * @param gmt
     * @return
     */
    private static String getGMTToChinaShortDate(String gmt) {
        if (StringUtils.isBlank(gmt)) {
            return null;
        }
        SimpleDateFormat s_sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        Date nowDate = null;
        try {
            nowDate = s_sdf.parse(gmt);

        } catch (ParseException pe) {
            nowDate = new Date();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowDate);
        calendar.add(Calendar.HOUR, +8);
        return sdf.format(calendar.getTime());
    }

}
